Micron Document
🎖️GitЯра🎖️


Displaying Raw • Download

feature/node/src/main/kotlin/org/meshtastic/feature/node/metrics/MetricsViewModel.kt 78274c792318331b11ab64cd28e58e829875b8c2 (78274c79) Text, 14.90 KB

T8b949e/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

Tff7b72package T7ee787org.meshtastic.feature.node.metrics

Tff7b72import T7ee787android.app.Application
Tff7b72import T7ee787android.net.Uri
Tff7b72import T7ee787androidx.lifecycle.SavedStateHandle
Tff7b72import T7ee787androidx.lifecycle.ViewModel
Tff7b72import T7ee787androidx.lifecycle.viewModelScope
Tff7b72import T7ee787androidx.navigation.toRoute
Tff7b72import T7ee787dagger.hilt.android.lifecycle.HiltViewModel
Tff7b72import T7ee787kotlinx.coroutines.Job
Tff7b72import T7ee787kotlinx.coroutines.flow.MutableStateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.StateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.asFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.combine
Tff7b72import T7ee787kotlinx.coroutines.flow.distinctUntilChanged
Tff7b72import T7ee787kotlinx.coroutines.flow.filterNotNull
Tff7b72import T7ee787kotlinx.coroutines.flow.map
Tff7b72import T7ee787kotlinx.coroutines.flow.mapLatest
Tff7b72import T7ee787kotlinx.coroutines.flow.toList
Tff7b72import T7ee787kotlinx.coroutines.flow.update
Tff7b72import T7ee787kotlinx.coroutines.launch
Tff7b72import T7ee787kotlinx.coroutines.withContext
Tff7b72import T7ee787org.jetbrains.compose.resources.getString
Tff7b72import T7ee787org.meshtastic.core.data.repository.DeviceHardwareRepository
Tff7b72import T7ee787org.meshtastic.core.data.repository.FirmwareReleaseRepository
Tff7b72import T7ee787org.meshtastic.core.data.repository.MeshLogRepository
Tff7b72import T7ee787org.meshtastic.core.data.repository.NodeRepository
Tff7b72import T7ee787org.meshtastic.core.data.repository.RadioConfigRepository
Tff7b72import T7ee787org.meshtastic.core.database.entity.MeshLog
Tff7b72import T7ee787org.meshtastic.core.database.model.Node
Tff7b72import T7ee787org.meshtastic.core.di.CoroutineDispatchers
Tff7b72import T7ee787org.meshtastic.core.model.DataPacket
Tff7b72import T7ee787org.meshtastic.core.navigation.NodesRoutes
Tff7b72import T7ee787org.meshtastic.core.service.ServiceAction
Tff7b72import T7ee787org.meshtastic.core.service.ServiceRepository
Tff7b72import T7ee787org.meshtastic.core.strings.Res
Tff7b72import T7ee787org.meshtastic.core.strings.fallback_node_name
Tff7b72import T7ee787org.meshtastic.core.ui.util.toPosition
Tff7b72import T7ee787org.meshtastic.feature.node.model.MetricsState
Tff7b72import T7ee787org.meshtastic.feature.node.model.TimeFrame
Tff7b72import T7ee787org.meshtastic.proto.MeshProtos
Tff7b72import T7ee787org.meshtastic.proto.MeshProtos.MeshPacket
Tff7b72import T7ee787org.meshtastic.proto.Portnums
Tff7b72import T7ee787org.meshtastic.proto.Portnums.PortNum
Tff7b72import T7ee787timber.log.Timber
Tff7b72import T7ee787java.io.BufferedWriter
Tff7b72import T7ee787java.io.FileNotFoundException
Tff7b72import T7ee787java.io.FileWriter
Tff7b72import T7ee787java.text.SimpleDateFormat
Tff7b72import T7ee787java.util.Locale
Tff7b72import T7ee787javax.inject.Inject

Tff7b72private Tff7b72const Tff7b72val Te6edf3DEFAULT_ID_SUFFIX_LENGTH Tff7b72= T79c0ff4

Tff7b72private Tff7b72fun Te6edf3MeshPacketTb4b4b4.Td2a8ffhasValidSignalTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3rxTime Tff7b72> T79c0ff0 Tff7b72&Tff7b72& Tb4b4b4(Te6edf3rxSnr Tff7b72!Tff7b72= T79c0ff0f Tff7b72&Tff7b72& Te6edf3rxRssi Tff7b72!Tff7b72= T79c0ff0Tb4b4b4) Tff7b72&Tff7b72& Tb4b4b4(Te6edf3hopStart Tff7b72> T79c0ff0 Tff7b72&Tff7b72& Te6edf3hopStart Tff7b72- Te6edf3hopLimit Tff7b72=Tff7b72= T79c0ff0Tb4b4b4)

Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffLongParameterListTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffTooManyFunctionsTa5d6ff"Tb4b4b4)
Tf0883e@HiltViewModel
Tff7b72class T56d364MetricsViewModel
Tf0883e@Inject
Tff7b72constructorTb4b4b4(
Te6edf3savedStateHandleTb4b4b4: Te6edf3SavedStateHandleTb4b4b4,
Tff7b72private Tff7b72val Te6edf3appTb4b4b4: Te6edf3ApplicationTb4b4b4,
Tff7b72private Tff7b72val Te6edf3dispatchersTb4b4b4: Te6edf3CoroutineDispatchersTb4b4b4,
Tff7b72private Tff7b72val Te6edf3meshLogRepositoryTb4b4b4: Te6edf3MeshLogRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3radioConfigRepositoryTb4b4b4: Te6edf3RadioConfigRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3serviceRepositoryTb4b4b4: Te6edf3ServiceRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3nodeRepositoryTb4b4b4: Te6edf3NodeRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3deviceHardwareRepositoryTb4b4b4: Te6edf3DeviceHardwareRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3firmwareReleaseRepositoryTb4b4b4: Te6edf3FirmwareReleaseRepositoryTb4b4b4,
Tb4b4b4) Tb4b4b4: Te6edf3ViewModelTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72private Tff7b72var Te6edf3destNumTb4b4b4: Tffa657Int? Tff7b72=
Te6edf3runCatching Tb4b4b4{ Te6edf3savedStateHandleTb4b4b4.Te6edf3toRouteTff7b72<Te6edf3NodesRoutesTb4b4b4.Te6edf3NodeDetailGraphTff7b72>Tb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3destNum Tb4b4b4}Tb4b4b4.Te6edf3getOrNullTb4b4b4(Tb4b4b4)

Tff7b72private Tff7b72var Te6edf3jobsTb4b4b4: Te6edf3Job? Tff7b72= Tff7b72null

Tff7b72private Tff7b72fun Te6edf3MeshLogTb4b4b4.Td2a8ffhasValidTracerouteTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3withTb4b4b4(Te6edf3fromRadioTb4b4b4.Te6edf3packetTb4b4b4) Tb4b4b4{ Te6edf3hasDecodedTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3decodedTb4b4b4.Te6edf3wantResponse Tff7b72&Tff7b72& Te6edf3from Tff7b72=Tff7b72= T79c0ff0 Tff7b72&Tff7b72& Te6edf3to Tff7b72=Tff7b72= Te6edf3destNum Tb4b4b4}

T8b949e/**
* Creates a fallback node for hidden clients or nodes not yet in the database. This prevents the detail screen from
* freezing when viewing unknown nodes.
*/
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffcreateFallbackNodeTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Te6edf3Node Tb4b4b4{
Tff7b72val Te6edf3userId Tff7b72= Te6edf3DataPacketTb4b4b4.Te6edf3nodeNumToDefaultIdTb4b4b4(Te6edf3nodeNumTb4b4b4)
Tff7b72val Te6edf3safeUserId Tff7b72= Te6edf3userIdTb4b4b4.Te6edf3padStartTb4b4b4(Te6edf3DEFAULT_ID_SUFFIX_LENGTHTb4b4b4, Ta5d6ff'0'Tb4b4b4)Tb4b4b4.Te6edf3takeLastTb4b4b4(Te6edf3DEFAULT_ID_SUFFIX_LENGTHTb4b4b4)
Tff7b72val Te6edf3longName Tff7b72= Te6edf3getStringTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3fallback_node_nameTb4b4b4) Tff7b72+ Ta5d6ff"Ta5d6ff Tffd700$Te6edf3safeUserIdTa5d6ff"
Tff7b72val Te6edf3defaultUser Tff7b72=
Te6edf3MeshProtosTb4b4b4.Te6edf3UserTb4b4b4.Te6edf3newBuilderTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3setIdTb4b4b4(Te6edf3userIdTb4b4b4)
Tb4b4b4.Te6edf3setLongNameTb4b4b4(Te6edf3longNameTb4b4b4)
Tb4b4b4.Te6edf3setShortNameTb4b4b4(Te6edf3safeUserIdTb4b4b4)
Tb4b4b4.Te6edf3setHwModelTb4b4b4(Te6edf3MeshProtosTb4b4b4.Te6edf3HardwareModelTb4b4b4.Te6edf3UNSETTb4b4b4)
Tb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)

Tff7b72return Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= Te6edf3nodeNumTb4b4b4, Te6edf3user Tff7b72= Te6edf3defaultUserTb4b4b4)
Tb4b4b4}

Tff7b72fun Td2a8ffgetUserTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4) Tff7b72= Te6edf3nodeRepositoryTb4b4b4.Te6edf3getUserTb4b4b4(Te6edf3nodeNumTb4b4b4)

Tff7b72fun Td2a8ffdeleteLogTb4b4b4(Te6edf3uuidTb4b4b4: Tffa657StringTb4b4b4) Tff7b72= Te6edf3viewModelScopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{ Te6edf3meshLogRepositoryTb4b4b4.Te6edf3deleteLogTb4b4b4(Te6edf3uuidTb4b4b4) Tb4b4b4}

Tff7b72fun Td2a8ffclearPositionTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3viewModelScopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{
Te6edf3destNumTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3meshLogRepositoryTb4b4b4.Te6edf3deleteLogsTb4b4b4(Tffa657itTb4b4b4, Te6edf3PortNumTb4b4b4.Te6edf3POSITION_APP_VALUETb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72fun Td2a8ffonServiceActionTb4b4b4(Te6edf3actionTb4b4b4: Te6edf3ServiceActionTb4b4b4) Tff7b72= Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3onServiceActionTb4b4b4(Te6edf3actionTb4b4b4) Tb4b4b4}

Tff7b72private Tff7b72val Te6edf3_state Tff7b72= Te6edf3MutableStateFlowTb4b4b4(Te6edf3MetricsStateTb4b4b4.Te6edf3EmptyTb4b4b4)
Tff7b72val Te6edf3stateTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3MetricsStateTff7b72> Tff7b72= Te6edf3_state

Tff7b72private Tff7b72val Te6edf3_environmentState Tff7b72= Te6edf3MutableStateFlowTb4b4b4(Te6edf3EnvironmentMetricsStateTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3environmentStateTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3EnvironmentMetricsStateTff7b72> Tff7b72= Te6edf3_environmentState

Tff7b72private Tff7b72val Te6edf3_timeFrame Tff7b72= Te6edf3MutableStateFlowTb4b4b4(Te6edf3TimeFrameTb4b4b4.Te6edf3TWENTY_FOUR_HOURSTb4b4b4)
Tff7b72val Te6edf3timeFrameTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3TimeFrameTff7b72> Tff7b72= Te6edf3_timeFrame

Tff7b72init Tb4b4b4{
Te6edf3initializeFlowsTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tff7b72fun Td2a8ffsetNodeIdTb4b4b4(Te6edf3idTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3destNum Tff7b72!Tff7b72= Te6edf3idTb4b4b4) Tb4b4b4{
Te6edf3destNum Tff7b72= Te6edf3id
Te6edf3initializeFlowsTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffLongMethodTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffinitializeFlowsTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3jobsTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3currentDestNum Tff7b72= Te6edf3destNum
Te6edf3jobs Tff7b72=
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3currentDestNum Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3launch Tb4b4b4{
Te6edf3nodeRepositoryTb4b4b4.Te6edf3nodeDBbyNum
Tb4b4b4.Te6edf3mapLatest Tb4b4b4{ Te6edf3nodes Tff7b72-Tff7b72> Te6edf3nodesTff7b72[Te6edf3currentDestNumTff7b72] Te6edf3to Te6edf3nodesTb4b4b4.Te6edf3keysTb4b4b4.Te6edf3firstOrNullTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3distinctUntilChangedTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3collect Tb4b4b4{ Tb4b4b4(Te6edf3nodeTb4b4b4, Te6edf3ourNodeTb4b4b4) Tff7b72-Tff7b72>
T8b949e// Create a fallback node if not found in database (for hidden clients, etc.)
Tff7b72val Te6edf3actualNode Tff7b72= Te6edf3node Tff7b72?: Te6edf3createFallbackNodeTb4b4b4(Te6edf3currentDestNumTb4b4b4)
Tff7b72val Te6edf3deviceHardware Tff7b72=
Te6edf3actualNodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3hwModelTb4b4b4.Te6edf3safeNumberTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3let Tb4b4b4{
Te6edf3deviceHardwareRepositoryTb4b4b4.Te6edf3getDeviceHardwareByModelTb4b4b4(Tffa657itTb4b4b4)
Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3node Tff7b72= Te6edf3actualNodeTb4b4b4,
Te6edf3isLocal Tff7b72= Te6edf3currentDestNum Tff7b72=Tff7b72= Te6edf3ourNodeTb4b4b4,
Te6edf3deviceHardware Tff7b72= Te6edf3deviceHardwareTb4b4b4.Te6edf3getOrNullTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3launch Tb4b4b4{
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3deviceProfileFlowTb4b4b4.Te6edf3collect Tb4b4b4{ Te6edf3profile Tff7b72-Tff7b72>
Tff7b72val Te6edf3moduleConfig Tff7b72= Te6edf3profileTb4b4b4.Te6edf3moduleConfig
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3isManaged Tff7b72= Te6edf3profileTb4b4b4.Te6edf3configTb4b4b4.Te6edf3securityTb4b4b4.Te6edf3isManagedTb4b4b4,
Te6edf3isFahrenheit Tff7b72= Te6edf3moduleConfigTb4b4b4.Te6edf3telemetryTb4b4b4.Te6edf3environmentDisplayFahrenheitTb4b4b4,
Te6edf3displayUnits Tff7b72= Te6edf3profileTb4b4b4.Te6edf3configTb4b4b4.Te6edf3displayTb4b4b4.Te6edf3unitsTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3launch Tb4b4b4{
Te6edf3meshLogRepositoryTb4b4b4.Te6edf3getTelemetryFromTb4b4b4(Te6edf3currentDestNumTb4b4b4)Tb4b4b4.Te6edf3collect Tb4b4b4{ Te6edf3telemetry Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3deviceMetrics Tff7b72= Te6edf3telemetryTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hasDeviceMetricsTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3powerMetrics Tff7b72= Te6edf3telemetryTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hasPowerMetricsTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3hostMetrics Tff7b72= Te6edf3telemetryTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hasHostMetricsTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3_environmentStateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3environmentMetrics Tff7b72=
Te6edf3telemetryTb4b4b4.Te6edf3filter Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3hasEnvironmentMetricsTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72&
Tffa657itTb4b4b4.Te6edf3environmentMetricsTb4b4b4.Te6edf3hasRelativeHumidityTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72&
Tffa657itTb4b4b4.Te6edf3environmentMetricsTb4b4b4.Te6edf3hasTemperatureTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72&
Tff7b72!Tffa657itTb4b4b4.Te6edf3environmentMetricsTb4b4b4.Te6edf3temperatureTb4b4b4.Te6edf3isNaNTb4b4b4(Tb4b4b4)
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3launch Tb4b4b4{
Te6edf3meshLogRepositoryTb4b4b4.Te6edf3getMeshPacketsFromTb4b4b4(Te6edf3currentDestNumTb4b4b4)Tb4b4b4.Te6edf3collect Tb4b4b4{ Te6edf3meshPackets Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3signalMetrics Tff7b72= Te6edf3meshPacketsTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hasValidSignalTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3launch Tb4b4b4{
Te6edf3combineTb4b4b4(
Te6edf3meshLogRepositoryTb4b4b4.Te6edf3getLogsFromTb4b4b4(Te6edf3nodeNum Tff7b72= T79c0ff0Tb4b4b4, Te6edf3PortNumTb4b4b4.Te6edf3TRACEROUTE_APP_VALUETb4b4b4)Tb4b4b4,
Te6edf3meshLogRepositoryTb4b4b4.Te6edf3getLogsFromTb4b4b4(Te6edf3currentDestNumTb4b4b4, Te6edf3PortNumTb4b4b4.Te6edf3TRACEROUTE_APP_VALUETb4b4b4)Tb4b4b4,
Tb4b4b4) Tb4b4b4{ Te6edf3requestTb4b4b4, Te6edf3response Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3tracerouteRequests Tff7b72= Te6edf3requestTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hasValidTracerouteTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3tracerouteResults Tff7b72= Te6edf3responseTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3collect Tb4b4b4{Tb4b4b4}
Tb4b4b4}

Te6edf3launch Tb4b4b4{
Te6edf3meshLogRepositoryTb4b4b4.Te6edf3getMeshPacketsFromTb4b4b4(
Te6edf3currentDestNumTb4b4b4,
Te6edf3PortNumTb4b4b4.Te6edf3POSITION_APP_VALUETb4b4b4,
Tb4b4b4)Tb4b4b4.Te6edf3collect Tb4b4b4{ Te6edf3packets Tff7b72-Tff7b72>
Tff7b72val Te6edf3distinctPositions Tff7b72=
Te6edf3packets
Tb4b4b4.Te6edf3mapNotNull Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3toPositionTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3asFlowTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3distinctUntilChanged Tb4b4b4{ Te6edf3oldTb4b4b4, Te6edf3new Tff7b72-Tff7b72>
Te6edf3oldTb4b4b4.Te6edf3time Tff7b72=Tff7b72= Te6edf3newTb4b4b4.Te6edf3time Tff7b72|Tff7b72|
Tb4b4b4(Te6edf3oldTb4b4b4.Te6edf3latitudeI Tff7b72=Tff7b72= Te6edf3newTb4b4b4.Te6edf3latitudeI Tff7b72&Tff7b72& Te6edf3oldTb4b4b4.Te6edf3longitudeI Tff7b72=Tff7b72= Te6edf3newTb4b4b4.Te6edf3longitudeITb4b4b4)
Tb4b4b4}
Tb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3positionLogs Tff7b72= Te6edf3distinctPositionsTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3launch Tb4b4b4{
Te6edf3meshLogRepositoryTb4b4b4.Te6edf3getLogsFromTb4b4b4(
Te6edf3currentDestNumTb4b4b4,
Te6edf3PortnumsTb4b4b4.Te6edf3PortNumTb4b4b4.Te6edf3PAXCOUNTER_APP_VALUETb4b4b4,
Tb4b4b4)Tb4b4b4.Te6edf3collect Tb4b4b4{ Te6edf3logs Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3paxMetrics Tff7b72= Te6edf3logsTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3launch Tb4b4b4{
Te6edf3firmwareReleaseRepositoryTb4b4b4.Te6edf3stableReleaseTb4b4b4.Te6edf3filterNotNullTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3collect Tb4b4b4{ Te6edf3latestStable Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3latestStableFirmware Tff7b72= Te6edf3latestStableTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3launch Tb4b4b4{
Te6edf3firmwareReleaseRepositoryTb4b4b4.Te6edf3alphaReleaseTb4b4b4.Te6edf3filterNotNullTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3collect Tb4b4b4{ Te6edf3latestAlpha Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3latestAlphaFirmware Tff7b72= Te6edf3latestAlphaTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3launch Tb4b4b4{
Te6edf3meshLogRepository
Tb4b4b4.Te6edf3getMyNodeInfoTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTff7b72?.Te6edf3firmwareEdition Tb4b4b4}
Tb4b4b4.Te6edf3distinctUntilChangedTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3collect Tb4b4b4{ Te6edf3firmwareEdition Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3firmwareEdition Tff7b72= Te6edf3firmwareEditionTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ffMetricsViewModel createdTa5d6ff"Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ffMetricsViewModel: destNum is null, skipping metrics flows initialization.Ta5d6ff"Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72fun Td2a8ffonClearedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72superTb4b4b4.Te6edf3onClearedTb4b4b4(Tb4b4b4)
Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ffMetricsViewModel clearedTa5d6ff"Tb4b4b4)
Tb4b4b4}

Tff7b72fun Td2a8ffsetTimeFrameTb4b4b4(Te6edf3timeFrameTb4b4b4: Te6edf3TimeFrameTb4b4b4) Tb4b4b4{
Te6edf3_timeFrameTb4b4b4.Te6edf3value Tff7b72= Te6edf3timeFrame
Tb4b4b4}

T8b949e/** Write the persisted Position data out to a CSV file in the specified location. */
Tff7b72fun Td2a8ffsavePositionCSVTb4b4b4(Te6edf3uriTb4b4b4: Te6edf3UriTb4b4b4) Tff7b72= Te6edf3viewModelScopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3mainTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3positions Tff7b72= Te6edf3stateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3positionLogs
Te6edf3writeToUriTb4b4b4(Te6edf3uriTb4b4b4) Tb4b4b4{ Te6edf3writer Tff7b72-Tff7b72>
Te6edf3writerTb4b4b4.Te6edf3appendLineTb4b4b4(
Ta5d6ff"Ta5d6ff\"Ta5d6ffdateTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6fftimeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6fflatitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6fflongitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6ffaltitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6ffsatsInViewTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6ffspeedTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6ffheadingTa5d6ff\"Ta5d6ff"Tb4b4b4,
Tb4b4b4)

Tff7b72val Te6edf3dateFormat Tff7b72= Te6edf3SimpleDateFormatTb4b4b4(Ta5d6ff"Ta5d6ff\"Ta5d6ffyyyy-MM-ddTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6ffHH:mm:ssTa5d6ff\"Ta5d6ff"Tb4b4b4, Te6edf3LocaleTb4b4b4.Te6edf3getDefaultTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3positionsTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3position Tff7b72-Tff7b72>
Tff7b72val Te6edf3rxDateTime Tff7b72= Te6edf3dateFormatTb4b4b4.Te6edf3formatTb4b4b4(Te6edf3positionTb4b4b4.Te6edf3time Tff7b72* T79c0ff1T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Tff7b72val Te6edf3latitude Tff7b72= Te6edf3positionTb4b4b4.Te6edf3latitudeI Tff7b72* T79c0ff1e-7
Tff7b72val Te6edf3longitude Tff7b72= Te6edf3positionTb4b4b4.Te6edf3longitudeI Tff7b72* T79c0ff1e-7
Tff7b72val Te6edf3altitude Tff7b72= Te6edf3positionTb4b4b4.Te6edf3altitude
Tff7b72val Te6edf3satsInView Tff7b72= Te6edf3positionTb4b4b4.Te6edf3satsInView
Tff7b72val Te6edf3speed Tff7b72= Te6edf3positionTb4b4b4.Te6edf3groundSpeed
Tff7b72val Te6edf3heading Tff7b72= Ta5d6ff"Ta5d6ff%.2fTa5d6ff"Tb4b4b4.Te6edf3formatTb4b4b4(Te6edf3positionTb4b4b4.Te6edf3groundTrack Tff7b72* T79c0ff1e-5Tb4b4b4)

T8b949e// date,time,latitude,longitude,altitude,satsInView,speed,heading
Te6edf3writerTb4b4b4.Te6edf3appendLineTb4b4b4(
Ta5d6ff"Tffd700$Te6edf3rxDateTimeTa5d6ff,Ta5d6ff\"Tffd700$Te6edf3latitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Tffd700$Te6edf3longitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Tffd700$Te6edf3altitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Tffd700$Te6edf3satsInViewTa5d6ff\"Ta5d6ff,Ta5d6ff\"Tffd700$Te6edf3speedTa5d6ff\"Ta5d6ff,Ta5d6ff\"Tffd700$Te6edf3headingTa5d6ff\"Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72suspend Tff7b72inline Tff7b72fun Td2a8ffwriteToUriTb4b4b4(Te6edf3uriTb4b4b4: Te6edf3UriTb4b4b4, Te6edf3crossinline Te6edf3blockTb4b4b4: Te6edf3suspend Tb4b4b4(Te6edf3BufferedWriterTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4) Tff7b72=
Te6edf3withContextTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3appTb4b4b4.Te6edf3contentResolverTb4b4b4.Te6edf3openFileDescriptorTb4b4b4(Te6edf3uriTb4b4b4, Ta5d6ff"Ta5d6ffwtTa5d6ff"Tb4b4b4)Tff7b72?.Te6edf3use Tb4b4b4{ Te6edf3parcelFileDescriptor Tff7b72-Tff7b72>
Te6edf3FileWriterTb4b4b4(Te6edf3parcelFileDescriptorTb4b4b4.Te6edf3fileDescriptorTb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Te6edf3fileWriter Tff7b72-Tff7b72>
Te6edf3BufferedWriterTb4b4b4(Te6edf3fileWriterTb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Te6edf3writer Tff7b72-Tff7b72> Te6edf3blockTb4b4b4.Te6edf3invokeTb4b4b4(Te6edf3writerTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3exTb4b4b4: Te6edf3FileNotFoundExceptionTb4b4b4) Tb4b4b4{
Te6edf3TimberTb4b4b4.Te6edf3eTb4b4b4(Te6edf3exTb4b4b4, Ta5d6ff"Ta5d6ffCan't write file errorTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.1s